"""

Copyright (C) 2011-2012 BIAGINI Nathan

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

"""

import pygame
from pygame.locals import *
import math

class Particle():
	"""

	Particle class.

	"""

	def __init__(self, life_frames, speed, surface_data, scale, color, alpha,
		end_scale, scale_change_freq, scale_change_step, end_color, color_change_freq, color_change_step, 
		end_alpha, alpha_change_freq, alpha_change_step, engine):

		"""

		@pos L{Tuple} : initial position of the particile given by the emitter
		@life_frames L{Int}: life time of particle in frames
		@speed L{Int} : speed of the particle in pixel/frames
		@angle L{Int} : angle using for calculing X and Y velocity components of the particle (given by the emitter)
		@surface_data L{Iterable} : data about the surface to use for the particle
		@scale L{Float} : multiply the size of the particle with this value to get another size
		@color L{Tuple} : RGB initial color of particle
		@alpha L{Int} : initial alpha value of the particle
		@end_scale L{Float} : final scale value, set it 0 to never change the particle scale
		@scale_change_freq L{Int} : number of frames to wait before changing the scale
		@scale_change_step L{Float} : value to update the scale with
		@end_color L{Tuple} : final color of the particle, set it 0 to never change the particle color during his life time 
		@color_change_freq L{Int} : number of frames to wait before changing the color
		@color_change_step L{Int} : value to update the color with
		@end_alpha L{Int} : the final alpha value, set it 0 to never change the alpha value of the particle
		@alpha_change_freq L{Int} : number of frames to wait before changing the alpha value
		@alpha_change_step L{Int} : value to update the alpha with
		@engine L{ParticleEngine} : instance of the engine that created the particle

		"""

		#all those values are choosen by the user of the engine via an XML file
		self.life_frames = life_frames
		self.speed = speed
		self.surface_data = surface_data
		self.color = color
		self.scale = scale
		self.alpha = alpha
		self.end_scale = end_scale
		self.scale_change_freq = scale_change_freq
		self.scale_change_step = scale_change_step
		self.end_color = end_color
		self.color_change_freq = color_change_freq
		self.color_change_step = color_change_step
		self.end_alpha = end_alpha
		self.alpha_change_freq = alpha_change_freq
		self.alpha_change_step = alpha_change_step
		self.engine = engine
	
		#position and angle are determinated by the engine
		self.x, self.y = 0, 0
		self.angle = None

		#x and y velocity components are calculted when the particle angle is know in setAngle method
		self.speedx, self.speedy = None, None

		#used for the particle update process
		self.current_life_frames = 0
		self.frames_since_last_color_change = 0
		self.frames_since_last_alpha_change = 0
		self.frames_since_last_scale_change = 0
		self.current_scale = self.scale #init the current particle scale with the initial scale
		if self.surface_data[0] == 'img':
			self.img_init_size = self.surface_data[1].get_width(), self.surface_data[1].get_height()

			#scale the particle with the initial scale value
			if self.scale is not 0:
				w = self.img_init_size[0] * self.scale
				h = self.img_init_size[1] * self.scale

				self.surface_data[1] = pygame.transform.smoothscale(self.surface_data[1], (w, h))
		
	def update(self):
		"""

		Update the particle.

		"""

		#update the particle position
		self.x += self.speedx
		self.y += self.speedy

		self.current_life_frames += 1 #update number of frames since this particle is created

		#check if the life time of the particle is elapsed
		if self.current_life_frames >= self.life_frames:
			self.engine.removeParticle(self) #then remove the particle

		if self.end_color is not 0:
			if self.frames_since_last_color_change >= self.color_change_freq:
				self.updateColor()

				self.frames_since_last_color_change = 0

			else:
				self.frames_since_last_color_change += 1

		if self.end_alpha is not 0:
			if self.frames_since_last_alpha_change >= self.alpha_change_freq:
				self.updateAlpha()

				self.frames_since_last_alpha_change = 0

			else:
				self.frames_since_last_alpha_change += 1

	def updateColor(self):
		"""

		Update the color of the particle.

		"""

		color = [self.color[0], self.color[1], self.color[2]]

		count = 0
		while count < 3:
			if self.color[count] < self.end_color[count]:
				color[count] += self.color_change_step 
				if color[count] > 255:
					color[count] = 255

			elif self.color[count] > self.end_color[count]:
				color[count] -= self.color_change_step
				if color[count] < 0:
					color[count] = 0

			count += 1

		self.color = tuple(color)

	def updateAlpha(self):
		"""

		Update the alpha value of particle surface.

		"""

		if self.alpha < self.end_alpha:
			self.alpha += self.alpha_change_step

		elif self.alpha > self.end_alpha:
			self.alpha -= self.alpha_change_step

	def draw(self, screen):
		"""

		Draw the particle.

		@screen L{pygame.Surface} : surface to draw the particle on

		"""

		if self.surface_data[0] == 'circle':
			pygame.draw.circle(screen, self.color, (self.x, self.y), self.surface_data[1])

		elif self.surface_data[0] == 'rect':
			pygame.draw.rect(screen, self.color, pygame.Rect((self.x, self.y), (self.surface_data[1][0], self.surface_data[1][1])))

		else:
			#this is neither a circle nor a rect surface, so it's a loaded image
		
			self.surface_data[1].set_alpha(self.alpha)
			screen.blit(self.surface_data[1], (self.x, self.y))

	def setPosition(self, pos):
		"""

		Set initial position of the particle.

		@pos L{Tuple} : initial position of the particle (given by the emitter)

		"""

		self.x, self.y = pos

	def setAngle(self, angle):
		"""

		Set the angle of the particle and calculates X and Y velocity components.

		@angle L{Int} : angle in degrees

		"""	

		self.angle = angle

		#X and Y velocity components
		self.speedx = math.sin(self.angle * (math.pi/180)) * self.speed
		self.speedy = math.cos(self.angle * (math.pi/180)) * self.speed * -1
